package start.demo01.erupt;

import java.util.LinkedList;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumer {
	private static Buffer buffer = new Buffer();
	public static void main(String[] args) {
		ExecutorService pool = Executors.newFixedThreadPool(2);
		pool.execute(new Producer());
		pool.execute(new Consumer());
		pool.shutdown();
	}
	private static class Producer implements Runnable{
		@Override
		public void run() {
			try {
				while(true) {
					Thread.sleep((int)(Math.random() * 1000));
					Task task = new Task();
					buffer.write(task);
					System.out.println("Producer[" + Thread.currentThread().getName() + "] put " + task);
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	private static class Consumer implements Runnable{
		@Override
		public void run() {
			try {
				while(true) {
					Thread.sleep((int)(Math.random() * 1000));
					System.out.println("Cousumer[" + Thread.currentThread().getName() + "] got " + buffer.read());
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	private static class Buffer{
		//指定缓存区大小为20
		private static final int CAPACITY = 20;
		private LinkedList<Task>queue = new LinkedList<>();
		private ReentrantLock lock = new ReentrantLock();
		//代表缓冲区未满
		private Condition notFull = lock.newCondition();
		//代表缓冲区非空条件
		private Condition notEmpty = lock.newCondition();
		
		/**
		 * 往队列中添加数据
		 * @param task
		 */
		public void write(Task task) {
			lock.lock();
			try {
				while(queue.size() >= CAPACITY) {//缓存区已满，等待
					System.out.println("notFull等待");
					notFull.await();//导致当前线程等到发信号或 interrupted 。释放锁
				}
				queue.offer(task);
				notEmpty.signal();//唤醒一个等待线程。
			}catch (InterruptedException e) {
				e.printStackTrace();
			}finally {
				lock.unlock();
			}
		}
		public Task read() {
			Task value = null;
			lock.lock();
			try {
				while(queue.isEmpty()) {
					System.out.println("notEmpty等待");
					notEmpty.await();//循环阻塞在这里
				}
				value = queue.remove();
				notFull.signal();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}finally {
				
			}
			return value;
		}
	}
	private static class Task{
		private String id;
		public Task() {
			this.id = UUID.randomUUID().toString();
		}
		@Override
		public String toString() {
			return "Task [id=" + id + "]";
		}
	}
}
